const gulp = require('gulp'); // Gulp
const gutil = require('gulp-util');
const watchify = require('watchify'); // 一个持续监视文件的改动，并且 只重新打包必要的文件 的 browserify 打包工具
const combiner = require('stream-combiner2'); // Stream-combiner2 捕获错误，不会中断程序
const uglify = require('gulp-uglify'); // 压缩JS代码和混淆变量
const browserify = require('browserify'); // 遵循CommonJS的模块化工具
const sourcemaps = require("gulp-sourcemaps"); // 生成.map文件方便调试打包后的代码
const source = require('vinyl-source-stream'); // 用于将Browserify的bundle()的输出转换为Gulp可用的[vinyl][]（一种虚拟文件格式）流
const buffer = require('vinyl-buffer'); // 用于将vinyl流转化为buffered vinyl文件
const htmlmin = require('gulp-htmlmin'); // 压缩HTML
const rev = require('gulp-rev'); // 把静态文件名改成hash的形式避免缓存
const revReplace = require("gulp-rev-replace"); // 替换出现在HTML中的静态文件引用，配合rev使用
const clean = require('gulp-clean');
const _ = require('lodash');
const fs = require('fs');

// 压缩混淆JS
gulp.task('script', ['clean'], function () {  
    
    return combiner.obj([
        gulp.src('./src/js/*.js'),
        sourcemaps.init(),
        uglify(), // 执行压缩
        rev(), // 根据文件内容生成hash附加到文件名
        sourcemaps.write('.'),
        gulp.dest('./dist/js'),
        rev.manifest(), // 生成一个json文件，内容为被转为hash名字的文件和它之前名字的键值对
        gulp.dest('./dist/js')
    ]).on('error', console.error.bind(console));
     // 任何在上面的 stream 中发生的错误，都不会抛出，
    // 而是会被监听器捕获
});

gulp.task('clean', function () {  
    return combiner.obj([
        gulp.src('./dist/js/*.*'),
        clean()
    ]);
});

gulp.task("html", ["script"], function(){
    var manifest = gulp.src("./dist/js/rev-manifest.json");
    return combiner.obj([
        gulp.src("./index.html"),
        htmlmin({
            collapseWhitespace: true,
            removeComments: true,
            minifyJS: true,
            minifyCSS: true
        }), // 压缩HTML
        revReplace({manifest: manifest}), // 利用经过rev处理后生成的json文件依次替换html内的src引用
        gulp.dest('./dist/html')
    ]);
   
});

// 模块化JS
var browser = browserify({
    basedir: '.',
    debug: true, 
    cache: {}, 
    packageCache: {},
    plugin: [watchify]
});

gulp.task("browserify",async function () {
    var fileArr = await new Promise((resolve, reject) => {
        var arr = [];
        fs.readdir('./src/js', (err, files) => {
            if (err) throw new Error(err);
            files.forEach((o, i) => {
                arr.push({file: './src/js/' + o, expose: o});
            });
            resolve(arr);
        });
    });
    
    return combiner.obj([
        browser.require(fileArr),
        browser.bundle(),
        source("bundle.js"),
        buffer(),
        sourcemaps.init({loadMaps: true}),
        uglify(),
        sourcemaps.write("."),
        gulp.dest("./dist/js")
    ]).on('error', console.error.bind(console));
});

// 当JS文件发生改变的时候，运行打包工具
browser.on('update', function () {   
    return combiner.obj([
        browser.bundle(),
        source("bundle.js"),
        buffer(),
        sourcemaps.init({loadMaps: true}),
        uglify(),
        sourcemaps.write("."),
        gulp.dest("./dist/js")
    ]).on('error', console.error.bind(console));
});

// 输出编译日志到终端
browser.on('log', gutil.log); 
